home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-04-25 | 15.3 KB | 565 lines | [TEXT/CWIE] |
- /*
- File: StorageClassCBIProtocol.c
-
- Contains: All code specific to handling the Command/Bulk/Interrupt Protocol
-
- Version: 1.3
-
- Copyright: © 1998-1999 by Apple Computer, Inc., all rights reserved.
- */
- // System Headers
- #include <DriverServices.h>
-
- // Class Driver Headers
- #include "StorageClassCBIProtocol.h"
-
- // ******************** CBI Protocol Functions **************************
- // CBI State Machine States
- enum
- {
- kCBIExecuteCommand = 1, // Begin execution of user command
- kCBIExecuteCommandCompletion, // Complete the user command
- kCBIBulkIOComplete, // Complete the bulk I/O
- kCBIReadInterruptComplete,
- kCBIGetStatusControlEndpointComplete,
- kCBIClearControlEndpointComplete,
- kCBIGetStatusBulkEndpointComplete,
- kCBIClearBulkEndpointComplete
- };
-
- // Structure for the global PB's
- struct StorageClassTransactionPB
- {
- USBPB usbPB;
- UInt8 cdb[kUSBStorageMaxCDBSize];
- UInt8 GetStatusBuffer[2]; // 2 bytes as specified in the USB spec
- Boolean busy;
- UInt32 flags; // Flags from StorageClassRequest pb
- UInt32 currentSGElement; // Scatter Gather element currently being transferred
- UInt32 currentSGCount; // Scatter Gather element currently being transferred
- StorageExecuteCommandPBPtr userPBPtr;
- StorageClassCompletionProcPtr completionProc;
- };
- typedef struct StorageClassTransactionPB StorageClassTransactionPB;
- typedef StorageClassTransactionPB *StorageClassTransactionPBPtr;
-
- static StorageClassTransactionPB gCommandPB; // Used only by StorageClassDriverExecuteCommand
-
- // Completion routines
- static void ExecuteCommandCompletion(USBPB* usbPB);
-
- OSStatus StorageClassCBIAbortCommand( StorageExecuteCommandPBPtr cmdPBPtr )
- {
- OSStatus err = noErr;
-
- if (( gCommandPB.busy == true ) && ( cmdPBPtr == gCommandPB.userPBPtr ))
- {
- // If there is a command pending, and the command is the one we want to
- // abort, go ahead and do it.
- USBReference pipeRef;
-
- switch ( gCommandPB.usbPB.usbRefcon )
- {
- case kCBIBulkIOComplete:
- {
- if (gCommandPB.flags & kStorageDataIn)
- {
- pipeRef = GetBulkInPipeRef();
- }
- else if (gCommandPB.flags & kStorageDataOut)
- {
- pipeRef = GetBulkOutPipeRef();
- }
- else
- {
- pipeRef = GetInterfaceRef();
- }
- }
- break;
-
- case kCBIReadInterruptComplete:
- {
- pipeRef = GetInterruptPipeRef();
- }
- break;
-
- default:
- {
- pipeRef = GetInterfaceRef();
- }
- break;
- }
-
- err = USBAbortPipeByReference(pipeRef);
- }
- else
- {
- err = abortErr;
- }
-
- return err;
- }
-
-
- OSStatus StorageClassCBIExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
- {
- OSStatus myErr;
-
- // check if we already have a read in progress, if so return error.
- if (gCommandPB.busy == true)
- {
- return kCommandBusyError;
- }
-
- BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
- gCommandPB.busy = true;
-
- InitParamBlock( GetInterfaceRef(), &gCommandPB.usbPB);
-
- // Get a local copy of the callers cdb
- BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kUSBStorageMaxCDBSize);
-
- gCommandPB.flags = cmdPBPtr->flags;
- gCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr; // Save the ptr to the callers PB
-
- // Make sure that the AutoSenseIsValid field is set to false so if we don't get the status, the client doesn't think we did
- cmdPBPtr->autoStatusIsValid = false;
-
- gCommandPB.usbPB.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);
- gCommandPB.usbPB.usb.cntl.BRequest = 0;
- gCommandPB.usbPB.usb.cntl.WValue = 0;
- gCommandPB.usbPB.usb.cntl.WIndex = 0;
-
- gCommandPB.usbPB.usbBuffer = (Ptr)&gCommandPB.cdb[0];
- gCommandPB.usbPB.usbReqCount = kUSBStorageMaxCDBSize;
- gCommandPB.usbPB.usbFlags = kUSBNo5SecTimeout;
-
- gCommandPB.usbPB.usbRefcon = kCBIExecuteCommand;
- gCommandPB.usbPB.usbCompletion = (USBCompletion)ExecuteCommandCompletion;
-
- myErr = USBDeviceRequest(&gCommandPB.usbPB);
- if (myErr != kRequestPending )
- {
- // The command completed immediately ( we probably got an error )
- // clear the PB's busy flag and return
- gCommandPB.busy = false;
- }
-
- cmdPBPtr->status = myErr;
- return myErr;
- }
-
-
- void ExecuteCommandCompletion(USBPB* usbPB)
- {
- StorageClassTransactionPBPtr transPtr;
- StorageExecuteCommandPBPtr cmdPBPtr;
-
- transPtr = (StorageClassTransactionPBPtr) usbPB;
-
- // Retrieve the callers pb
- cmdPBPtr = (StorageExecuteCommandPBPtr) transPtr->userPBPtr;
-
- switch(usbPB->usbRefcon)
- {
- case kCBIExecuteCommand: // Device request completion
- {
- // First check to see if an error occurred on the command out
- if (usbPB->usbStatus != noErr)
- {
- cmdPBPtr->status = GetStatusEndpointStatus( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, (Ptr) transPtr->GetStatusBuffer, kCBIGetStatusControlEndpointComplete);
- }
- else
- {
- // If there is to be no data transfer then we are done and can return to the caller
- // We will only get to here if no Error occurred.
- if (transPtr->flags & kStorageNoData)
- {
- cmdPBPtr->status = noErr;
- break;
- }
-
- // Setup the usb pb for either bulk in or out
- if (transPtr->flags & kStorageDataIn)
- {
- InitParamBlock( GetBulkInPipeRef(), usbPB);
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- InitParamBlock( GetBulkOutPipeRef(), usbPB);
- }
-
- if (transPtr->flags & kStorageSGBuffer)
- {
- // We have a scatter-gather transfer
- USBSGListPtr theSGList;
- USBSGElementPtr currentSGElement;
-
- transPtr->currentSGElement = 0;
- transPtr->currentSGCount = 0;
- theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
- currentSGElement = &theSGList->sgElementList[0];
- if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
- {
- usbPB->usbReqCount = kUSBMaxBulkTransfer;
- }
- else
- {
- usbPB->usbReqCount = currentSGElement->SGCount;
- }
-
- usbPB->usbBuffer = currentSGElement->SGAddr;
- }
- else
- {
- // We have a single buffer transfer
- if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
- {
- usbPB->usbReqCount = kUSBMaxBulkTransfer;
- }
- else
- {
- usbPB->usbReqCount = cmdPBPtr->expectedCount;
- }
-
- usbPB->usbBuffer = cmdPBPtr->userBuffer;
- }
-
- usbPB->usbRefcon = kCBIBulkIOComplete;
- usbPB->usbActCount = 0;
- usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
-
- // Start a bulk in or out transaction
- if (transPtr->flags & kStorageDataIn)
- {
- cmdPBPtr->status = USBBulkRead(&transPtr->usbPB);
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- cmdPBPtr->status = USBBulkWrite(&transPtr->usbPB);
- }
- }
- }
- break;
-
- case kCBIBulkIOComplete:
- {
- cmdPBPtr->actualCount += usbPB->usbActCount; // Update the users byte count
-
- if (usbPB->usbStatus != noErr)
- {
- // Either an error occurred on transfer or we did not get all the data we requested.
- // In either case, this transfer is complete, clean up and return an error to the client.
- if (GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass )
- {
- InitParamBlock( GetInterruptPipeRef(), usbPB); // Read the Status from the interrupt
-
- usbPB->usbBuffer = (Ptr)cmdPBPtr->autoStatus;
- usbPB->usbReqCount = kUSBStorageAutoStatusSize;
- usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
- usbPB->usbRefcon = kCBIReadInterruptComplete;
-
- cmdPBPtr->status = USBIntRead( usbPB );
- }
- //else if (GetInterfaceSubclass() == kUSBStorageUFISubclass)
- else
- {
- cmdPBPtr->status = GetStatusEndpointStatus( usbPB, GetInterfaceRef(), ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusControlEndpointComplete);
- }
- }
- else if (( cmdPBPtr->actualCount != cmdPBPtr->expectedCount) && ( usbPB->usbActCount == usbPB->usbReqCount ))
- {
- // If we have not yet transfered all the data and there are no Errors and we did not receive a short packet.
- // Setup the usb pb for either bulk in or out
- UInt32 actCount = usbPB->usbActCount;
-
- if (transPtr->flags & kStorageDataIn)
- {
- InitParamBlock( GetBulkInPipeRef(), usbPB);
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- InitParamBlock( GetBulkOutPipeRef(), usbPB);
- }
-
- if (transPtr->flags & kStorageSGBuffer)
- {
- // We have a scatter-gather transfer
- USBSGListPtr theSGList;
- USBSGElementPtr currentSGElement;
-
- transPtr->currentSGCount += actCount;
- theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
- currentSGElement = &theSGList->sgElementList[transPtr->currentSGElement];
-
- if ( transPtr->currentSGCount >= currentSGElement->SGCount)
- {
- // Move on to next SG segment
- transPtr->currentSGElement++;
- currentSGElement = &theSGList->sgElementList[transPtr->currentSGElement];
- transPtr->currentSGCount = 0;
- if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
- {
- usbPB->usbReqCount = kUSBMaxBulkTransfer;
- }
- else
- {
- usbPB->usbReqCount = currentSGElement->SGCount;
- }
-
- usbPB->usbBuffer = currentSGElement->SGAddr;
- }
- else
- {
- if ( (currentSGElement->SGCount - transPtr->currentSGCount) > kUSBMaxBulkTransfer )
- {
- usbPB->usbReqCount = kUSBMaxBulkTransfer;
- }
- else
- {
- usbPB->usbReqCount = (currentSGElement->SGCount - transPtr->currentSGCount);
- }
-
- usbPB->usbBuffer = currentSGElement->SGAddr + transPtr->currentSGCount;
- }
- }
- else
- {
- if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
- {
- usbPB->usbReqCount = kUSBMaxBulkTransfer;
- }
- else
- {
- usbPB->usbReqCount = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
- }
-
- usbPB->usbBuffer = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
- }
-
- usbPB->usbRefcon = kCBIBulkIOComplete;
- usbPB->usbActCount = 0;
- usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
-
- // Continue a bulk in or out transaction
- if (transPtr->flags & kStorageDataIn)
- {
- cmdPBPtr->status = USBBulkRead(&transPtr->usbPB);
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- cmdPBPtr->status = USBBulkWrite(&transPtr->usbPB);
- }
- }
- else
- {
- if (( GetInterruptPipeRef() != 0 ) && (transPtr->flags & kStorageUseCommandCompletionInt))
- {
- // We have an interrupt pipe, and device uses it to determine a command is done
- InitParamBlock( GetInterruptPipeRef(), usbPB);
-
- usbPB->usbBuffer = (Ptr)cmdPBPtr->autoStatus;
- usbPB->usbReqCount = kUSBStorageAutoStatusSize;
- usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
- usbPB->usbRefcon = kCBIReadInterruptComplete;
-
- cmdPBPtr->status = USBIntRead( usbPB ); // Read the Status from the interrupt
- }
- else
- {
- cmdPBPtr->status = noErr;
- }
- }
- }
- break;
-
- case kCBIReadInterruptComplete:
- {
- // What should the status really be, should probably process and return
- // a relevent error.
- if ((usbPB->usbStatus == noErr) && ((GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass ) || ( GetInterfaceSubclass() == kUSBStorageUFISubclass )))
- {
- cmdPBPtr->autoStatusIsValid = true;
-
- // Decide what error to return based on the Interrupt data
- if (( cmdPBPtr->autoStatus[0] == 0x00 ) && ( cmdPBPtr->autoStatus[1] == 0x00 ))
- {
- cmdPBPtr->status = noErr;
- }
- else
- {
- cmdPBPtr->status = kUSBInternalErr;
- }
- }
- else
- {
- // The Class doesn't know how to interpret the data
- // return an error and mark interrupt data as invalid
- cmdPBPtr->autoStatusIsValid = false;
- cmdPBPtr->status = kUSBInternalErr;
- }
- }
- break;
-
- case kCBIGetStatusControlEndpointComplete:
- {
- if (usbPB->usbStatus == noErr)
- {
- if (((transPtr->GetStatusBuffer[0] & 1) == 1 ) || (GetInterfaceSubclass() == kUSBStorageUFISubclass))
- {
- // This endpoint was stalled, go ahead and clear it
- cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, kCBIClearControlEndpointComplete);
- }
- else
- {
- if ( transPtr->flags & kStorageNoData )
- {
- cmdPBPtr->actualCount = 0;
- cmdPBPtr->status = kUSBInternalErr;
- }
- else
- {
- // Check if the bulk endpoint was stalled
- USBPipeRef pipeRef = 0;
-
- if (transPtr->flags & kStorageDataIn)
- {
- pipeRef = GetBulkInPipeRef();
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- pipeRef = GetBulkOutPipeRef();
- }
- else
- {
- pipeRef = GetInterfaceRef();
- }
-
- cmdPBPtr->status = GetStatusEndpointStatus( usbPB, pipeRef, ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusBulkEndpointComplete);
- }
- }
- }
- else
- {
- // An error occurred to GET_STATUS ( shouldn't happen!!) reset the endpoint anyway
- cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, kCBIClearControlEndpointComplete);
- }
- }
- break;
-
- case kCBIClearControlEndpointComplete:
- {
- if (usbPB->usbStatus == noErr)
- {
- if ( transPtr->flags & kStorageNoData )
- {
- cmdPBPtr->actualCount = 0;
- cmdPBPtr->status = kUSBInternalErr;
- }
- else
- {
- // Check if the bulk endpoint was stalled
- USBPipeRef pipeRef = 0;
-
- if (transPtr->flags & kStorageDataIn)
- {
- pipeRef = GetBulkInPipeRef();
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- pipeRef = GetBulkOutPipeRef();
- }
- else
- {
- pipeRef = GetInterfaceRef();
- }
-
- cmdPBPtr->status = GetStatusEndpointStatus( usbPB, pipeRef, ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusBulkEndpointComplete);
- }
- }
- else
- {
- cmdPBPtr->status = usbPB->usbStatus;
- }
- }
- break;
-
- case kCBIGetStatusBulkEndpointComplete:
- {
- if (usbPB->usbStatus == noErr)
- {
- if (( (transPtr->GetStatusBuffer[0] & 1) == 1 ) || (GetInterfaceSubclass() == kUSBStorageUFISubclass))
- {
- USBPipeRef pipeRef = 0;
-
- if (transPtr->flags & kStorageDataIn)
- {
- pipeRef = GetBulkInPipeRef();
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- pipeRef = GetBulkOutPipeRef();
- }
- else
- {
- pipeRef = GetInterfaceRef();
- }
-
- cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, pipeRef, ExecuteCommandCompletion, kCBIClearBulkEndpointComplete);
- }
- else
- {
- cmdPBPtr->actualCount = 0;
- cmdPBPtr->status = kUSBInternalErr;
- }
- }
- else
- {
- USBPipeRef pipeRef = 0;
-
- if (transPtr->flags & kStorageDataIn)
- {
- pipeRef = GetBulkInPipeRef();
- }
- else if (transPtr->flags & kStorageDataOut)
- {
- pipeRef = GetBulkOutPipeRef();
- }
- else
- {
- pipeRef = GetInterfaceRef();
- }
-
- cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, pipeRef, ExecuteCommandCompletion, kCBIClearBulkEndpointComplete);
- }
- }
- break;
-
- case kCBIClearBulkEndpointComplete:
- {
- cmdPBPtr->actualCount = 0;
- cmdPBPtr->status = kUSBInternalErr;
- }
- break;
-
- default:
- {
- cmdPBPtr->actualCount = 0;
- cmdPBPtr->status = kUSBInternalErr;
- }
- break;
- }
-
- // If the command has been completed ( no longer pending ), call the clients completion routine.
- if (cmdPBPtr->status != kRequestPending )
- {
- BlockZero ( usbPB, sizeof(USBPB));
- transPtr->busy = false;
- if(cmdPBPtr->completionProc != nil)
- {
- (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
- }
- }
- }
-
-